#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>
#include <utility>
#include <cassert>
#include "Sock.hpp"
#include "Epoller.hpp"
#include "Log.hpp"
#include "Util.hpp"

class Connection;
class TcpServer;
static const uint16_t defaultport = 8080;
static const int defalutnum = 64;
using func_t = std::function<void(Connection *con)>;

// 每一个套接字都对应有一个connection结构
class Connection
{
public:
    Connection(int sock, TcpServer *tsr)
        : _sock(sock), _tsr(tsr)
    {
    }
    ~Connection()
    {
    }

    // 事件注册
    void Register(func_t r, func_t s, func_t e)
    {
        _Recv = r;
        _Send = s;
        _Excep = e;
    }

    void Close()
    {
        close(_sock);
    }

public:
    int _sock;
    std::string inbuffer;  // 输入缓冲区
    std::string outbuffer; // 输出缓冲区

    func_t _Recv;    // 从sock中读取
    func_t _Send;    // 向sock中写入
    func_t _Excep;   // 处理sock中的IO出错问题
    TcpServer *_tsr; // 回执指针
};

class TcpServer
{
private:
    void Recv(Connection *con)
    {
        // 处理读事件
        char buffer[2048];
        while (true)
        {
            int n = recv(con->_sock, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                // 读取成功，将数据添加到输入缓冲区当中
                con->inbuffer += buffer;
                logMessage(DEBUG, "\n%s", con->inbuffer.c_str());
                // 处理数据
                _serive(con);
            }
            else if (n == 0)
            {
                if (con->_Excep)
                {
                    con->_Excep(con);
                    return; // 异常事件调用不能继续向下走
                }
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    if (con->_Excep)
                    {
                        con->_Excep(con);
                        return;
                    }
                }
            }
        }
    }

    void Send(Connection *con)
    {
        // 输入缓冲区一直有空间，一直就绪
        while (true)
        {
            ssize_t n = send(con->_sock, con->outbuffer.c_str(), con->outbuffer.size(), 0);
            if (n > 0)
            {
                if (con->outbuffer.empty())
                {
                    break;
                }
                else
                {
                    con->outbuffer.erase(0, n);
                }
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    if (con->_Excep)
                    {
                        con->_Excep(con);
                        return;
                    }
                }
            }
        }

        // 判断是否，发送完毕，如果发送完毕直接关闭对写事件的关心，没有就开启对写事件的关心
        if (!con->outbuffer.empty())
        {
            con->_tsr->EnableReadWrite(con, true, true);
        }
        else
        {
            con->_tsr->EnableReadWrite(con, true, false);
        }
    }

    void Excep(Connection *con)
    {
        // 直接从epoll中移除套接字，并关闭，并从connections中移除
        logMessage(DEBUG, "Excep begin ....");
        _epoller.Control(con->_sock, 0, EPOLL_CTL_DEL);
        con->Close();
        _connections.erase(con->_sock);
        logMessage(DEBUG, "关闭套接字: %d", con->_sock);
        delete con;
    }

    void EnableReadWrite(Connection *con, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        _epoller.Control(con->_sock, events, EPOLL_CTL_MOD);
    }

    // 为每一个sock构建connection结构，并添加到 connections 当中
    void AddConnection(int sock, uint32_t events, func_t recv, func_t send, func_t excep)
    {
        // 需要将sock添加到epoll模型中
        if (events & EPOLLIN)
        {
            // ET模式下的读事件
            Util::SetNonBlock(sock);
        }
        Connection *con = new Connection(sock, this);
        // 为sock注册对应的回执函数
        con->Register(recv, send, excep);

        // 将对应sock关联的事件，注入到 epoll当中
        bool n = _epoller.AddEvents(sock, events);
        assert(n);
        (void)n;
        // 添加到 connections中
        _connections.insert(std::pair<int, Connection *>(sock, con));
        logMessage(NORMAL, "AddConnetion sock: %d success ", sock);
    }

public:
    TcpServer(func_t func, uint16_t port = defaultport)
        : _port(port), _serive(func)
    {
    }
    ~TcpServer()
    {
        _sock.Close();
        _epoller.Close();
        if (_recv)
        {
            delete[] _recv;
        }
    }

    void InitServer()
    {
        // 套接字
        _sock.Socket();
        _sock.Bind(_port);
        _sock.Listen();

        // 创建epoll
        _epoller.CreateEpoll();
        // 为 listensock 创建一个 connection 结构 只关心读事件和ET模式
        AddConnection(_sock.Fd(), EPOLLIN | EPOLLET,
                      std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

        _recv = new struct epoll_event[defalutnum];
        _num = defaultnum;
        logMessage(DEBUG, "Init Server success");
    }

    // 监听套接字的获取连接
    void Accepter(Connection *con)
    {
        logMessage(DEBUG, "Accepter begin ...");
        for (;;)
        {
            std::string clientIP;
            uint16_t clientPort;
            int err;
            int sock = _sock.Accept(&clientIP, &clientPort, &err);
            if (sock > 0)
            {
                // 添加 connection结构
                AddConnection(sock, EPOLLIN | EPOLLET,
                              std::bind(&TcpServer::Recv, this, std::placeholders::_1),
                              std::bind(&TcpServer::Send, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excep, this, std::placeholders::_1));
                logMessage(DEBUG, "get a new link [%s,%d]", clientIP.c_str(), clientPort);
            }
            else
            {
                // 根据错误码进一步判断
                if (err == EAGAIN || err == EWOULDBLOCK)
                {
                    // 数据未就绪
                    break;
                }
                else if (err == EINTR)
                {
                    // 中断信号
                    continue;
                }
                else
                {
                    break;
                }
            }
        }
        logMessage(DEBUG, "Accepter end ...");
    }

    bool IsConnectionExit(int sock)
    {
        auto pos = _connections.find(sock);
        if (pos != _connections.end())
        {
            return true;
        }

        return false;
    }

    void Loop(int timeout)
    {
        // 有多少个事件就绪
        int n = _epoller.Wait(_recv, _num, timeout);
        for (int i = 0; i < n; i++)
        {
            int sock = _recv[i].data.fd;
            uint32_t events = _recv[i].events;

            // 将所有的异常事件转化为 写就绪 | 读就绪
            if (events & EPOLLERR)
            {
                events |= (EPOLLIN | EPOLLOUT);
            }

            if (events & EPOLLHUP) // 挂断（客户端）
            {
                events |= (EPOLLIN | EPOLLOUT);
            }

            // 读事件  connection是否存在 读任务是否设置
            if ((events & EPOLLIN) && (IsConnectionExit(sock)) && _connections[sock]->_Recv)
            {
                _connections[sock]->_Recv(_connections[sock]); // 传递就是 connection 指针
            }
            if ((events & EPOLLOUT) && (IsConnectionExit(sock)) && _connections[sock]->_Send)
            {
                _connections[sock]->_Send(_connections[sock]);
            }
        }
    }

    void Dispatch()
    {
        int timeout = 1000;
        while (true)
        {
            // 一直进行任务的派发
            Loop(timeout);
            // logMessage(DEBUG, "timeout ...");
        }
    }

private:
    Sock _sock;
    Epoller _epoller;
    uint16_t _port;
    struct epoll_event *_recv;
    int _num;
    func_t _serive; // 处理任务事件
    std::unordered_map<int, Connection *> _connections;
};